/**
 * @file hoc-curd
 * @author liyong18@baidu.com
 */
/* eslint fecs-indent: [0, "space", 2, 2] */

import * as React from 'react';
import {
  Component,
  PureComponent,
  PropTypes
} from 'react';
import {findDOMNode} from 'react-dom';
import {Renderer, render, filter} from '../renderer';
import * as cx from 'classnames';
import * as assign from 'object-assign';
import * as update from 'react-addons-update';
// import * as ReactPaginate from 'react-paginate';
import {DropTarget } from 'react-dnd';
import {findByAttrValue} from '../../util/helper';
import  * as ReactTooltip from 'react-tooltip';
import {container} from '../propTypes';
import * as partition from 'lodash/partition';
import * as pick from 'lodash/pick';
import * as isEmpty from 'lodash/isEmpty';
import './table/tool/col-control';
import {Pagination} from 'react-bootstrap';
import {AutoAffix} from 'react-overlays';
import TooltipWrapper from '../../widgets/tooltip';
import {evalExpression} from '../util';
import {diff} from './crud';

const CARD_TYPE = 'row';

export const Enhance = config => ComposedComponent => {
  @DropTarget(CARD_TYPE, {
    drop() {
    }
  }, connect => ({
    connectDropTarget: connect.dropTarget()
  }))
  class HocCrud extends PureComponent {
    static propTypes = {
      bulkActions: PropTypes.arrayOf(PropTypes.shape({
        label: PropTypes.string,
        actionType: PropTypes.string.isRequired
      })),
      defaultChecked: PropTypes.bool,
      className: PropTypes.string,
      tableWrapClassName: PropTypes.string,
      tableClassName: PropTypes.string,
      draggable: PropTypes.bool,
      columns: PropTypes.arrayOf(PropTypes.object),
      data: PropTypes.object,
      rows: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.object, PropTypes.string])),

      toolbar: container,
      title: PropTypes.string,
      loading: PropTypes.bool,

      // order by
      orderBy: PropTypes.string,
      orderDir: PropTypes.oneOf(['asc', 'desc']),

      // pagination
      currentPage: PropTypes.number.isRequired,
      lastPage: PropTypes.number.isRequired,
      perPage: PropTypes.number.isRequired,
      total: PropTypes.number.isRequired,
      hasMore: PropTypes.bool,

      switchPerPage: PropTypes.any,
      showPageInfo: PropTypes.bool.isRequired,

      columnsTogglable: PropTypes.bool,
      // events
      onOrderByToggle: PropTypes.func,
      onPerPageChange: PropTypes.func,
      onPaginationChange: PropTypes.func,
      onBulkAction: PropTypes.func,
      onAction: PropTypes.func,
      onSaveOrder: PropTypes.func,
      onQuickSave: PropTypes.func
    };

    static defaultProps = assign({
      title: '',
      className: 'panel-default',
      toolbarClassName: '',
      tableWrapClassName: 'table-responsive',
      tableClassName: 'table-striped',
      placeholder: '没有数据',
      primaryField: 'id',

      // pagination
      currentPage: 1, // 当前第几页
      lastPage: 1, // 总共有多少页
      perPage: 10, // 每页多少个
      total: 0, // 总共多少个
      hasMore: false,

      switchPerPage: false, // 是否能切换页码
      showPageInfo: true, // 是否显示数据信息
      showPagination: true,
      showPageInfoOnHeader: false,
      defaultChecked: false, // 默认是否选中

      hasHeader: true,
      hasToolBar: true,
      hasTool: true,
      hasOrder: true,
      hasColumTool: true,
      hasBulk: true,
      hasBulkCheckbox: false,
      hasFooter: true,
      noPanel: false,
      toolbarInline: false,
      showHeader: true,
      showFooter: true,
      headerAffix: false
    }, config || {});

    constructor(props) {
      super(props);
      const rows = this.buildRows(props, 0);
      let columnsTogglable = props.columnsTogglable;

      if (typeof columnsTogglable === 'undefined') {
        columnsTogglable = props.columns && props.columns.length > 5;
      }

      this.state = {
        rows,
        pristineRows: rows && rows.concat(),
        bulkAction: null,
        dragging: false,
        triggerBuild: true,
        columnsTogglable,
        columnsTogglableCol: null,
        columns: props.columns,

        // 本地排序
        localOrderBy: '',
        localOrderDir: '',

        highlightId: 0,
        pageNum: props.currentPage || 1
      };

      // 将全选或全不选,传入bool
      this.toggleAll = this.toggleAll.bind(this);

      // 将某一项选或者不选,传入(bool, item)
      this.toggle = this.toggle.bind(this);

      // 将dragging和columnsTogglable设置下，不需要传值
      this.toggleDragging = this.toggleDragging.bind(this);

      // 传入id，返回{item, index},这个index是现在这个元素在数组中的位置，而不是之前的位置
      this.findRow = this.findRow.bind(this);

      // 将某一个id移动到指定的位置,传入(id, index)
      this.moveRow = this.moveRow.bind(this);

      // 确定将某个元素移动，传入id, 至于index的话就是当前位置。会设置$modified等属性
      this.moveRowConfirm = this.moveRowConfirm.bind(this);

      // 将rows和dragging,columnsTogglable还原
      this.reset = this.reset.bind(this);

      // 改变item的值，传入(item, newValue, fn),fn为回调函数
      this.changeRow = this.changeRow.bind(this);

      // 把modified为true的拿出来，然后调onQuick方法
      this.quickSave = this.quickSave.bind(this);

      // 保存顺序，什么都不需要填,直接将rows传出去
      this.saveOrder = this.saveOrder.bind(this);

      // bulk操作，将$checked的拿出来操作
      this.bulkGo = this.bulkGo.bind(this);

      // 这个是快速编辑，但是不保存
      this.handleFieldValueChange = this.handleFieldValueChange.bind(this);

      // 这个是快速编辑，要保存
      this.handleFieldValueSave = this.handleFieldValueSave.bind(this);

      // 这个是给toggled组件用的
      this.receiveCol = this.receiveCol.bind(this);

      // 这个是给本地排序用的
      this.localSortByName = this.localSortByName.bind(this);

      this.setColumnsTogglableCol = this.setColumnsTogglableCol.bind(this);
      this.handleAction = this.handleAction.bind(this);
      this.handleHighlight = this.handleHighlight.bind(this);
      this.handlePageNumChange = this.handlePageNumChange.bind(this);
    }

    componentWillMount() {
      const {crudRef} = this.props;

      crudRef && crudRef(this);
    }

    componentWillReceiveProps(nextProps) {
      const props = this.props;
      const {
        localOrderBy,
        localOrderDir
      } = this.state;
      if (
        props.rows !== nextProps.rows
        || props.draggable !== nextProps.draggable
        || props.bulkActions !== nextProps.bulkActions
      ) {
        const rows = this.buildRows(nextProps);
        this.tooltipRebuild = true;

        this.setState({
          rows,
          pristineRows: rows && rows.concat(),
          bulkAction: null,
          dragging: false,
          triggerBuild: !this.state.triggerBuild,
          pageNum: nextProps.currentPage || 1
        }, ()=>{
          if (props.rows !== nextProps.rows && localOrderBy) {
            this.localSortByName(localOrderBy, false);
          }
        });
      }


    }

    componentDidUpdate() {
      if (this.tooltipRebuild) {
        this.tooltipRebuild = false;
        ReactTooltip.rebuild();
      }
    }

    localSortByName(name, toggle = true){
      const {
        localOrderBy,
        localOrderDir,
        rows
      } = this.state;

      let nextLocalOrderDir = toggle ? 'asc' : localOrderDir;
      if (localOrderBy == name && toggle) {
        switch(localOrderDir) {
          case 'asc':
            nextLocalOrderDir = 'desc';
            break;
          case 'desc':
            nextLocalOrderDir = 'asc';
            break;
          default:
            nextLocalOrderDir = 'asc';
            break;
        }
      }

      if (rows) {
        rows.sort((a,b) => {
          let a1 = a[name],b1 = b[name];
          if (!isNaN(+a1) && !isNaN(+b1)) {
            a1 = +a1;
            b1 = +b1;
          }

          if(nextLocalOrderDir == 'asc') {
            return a1 > b1 ? 1 : a1 < b1 ? -1 : 0;
          } else {
            return a1 > b1 ? -1 : a1 < b1 ? 1 : 0;
          }
        });
      }

      this.setState({
        rows: this.buildRows(assign({}, this.props, {rows})),
        localOrderDir: nextLocalOrderDir,
        localOrderBy: name
      });
    }

    buildRows(props, highlightId = this.state.highlightId) {
      let id = 1;
      let primaryField = props.primaryField;
      const defaultChecked = props.defaultChecked;

      return props.rows && props.rows.map((item, index) => {
          item = typeof item === 'string' ? {text: item} : item;

          return assign({
            // 这两个都是给排序用的
            $id: item[primaryField] || id++,
            $index: index,

            // 这个是给快速保存用的
            $pristine: item,

            // 这个是给bulk操作用的
            $checked: defaultChecked,

            // 这个是给排序用的
            $modified: false,

            $highlight: item[primaryField] == highlightId
          }, item);
        });
    }

    toggle(checked, item) {
      const rows = this.state.rows;
      const idx = item.hasOwnProperty('$index') ? item.$index : rows.indexOf(item);

      this.setState({
        rows: update(rows, {
          $splice: [
            [idx, 1, assign({}, item, {
              $checked: checked
            })]
          ]
        })
      });
    }

    toggleAll(checkedAll) {
      const rows = this.state.rows;

      this.setState({
        rows: rows.map(item => assign({}, item, {
          $checked: checkedAll
        }))
      });
    }

    toggleDragging() {
      let {
        dragging,
        triggerBuild
      } = this.state;

      this.setState({
        dragging: !this.state.dragging,
        triggerBuild: !triggerBuild
      });
    }

    receiveCol(cols) {
      this.setState({
        columns: cols
      });
    }

    setColumnsTogglableCol(col) {
      this.setState({columnsTogglableCol: col});
    }
    findRow(id) {
      const {rows} = this.state;
      const item = findByAttrValue(rows, '$id', id);

      return {
        item,
        index: rows.indexOf(item)
      };
    }

    moveRow(dragId, hoverIndex) {
      const {
        index,
        item
      } = this.findRow(dragId);

      this.setState(update(this.state, {
        rows: {
          $splice: [
            [index, 1],
            [hoverIndex, 0, item]
          ]
        }
      }))
    }

    moveRowConfirm(rowId) {
      const {
        index: cIndex
      } = this.findRow(rowId);

      // 检查确实需要移动, 如果可以不移动,则还原 isModified 属性
      const rows = this.state.rows;
      const length = rows.length;
      const toUpdate = [];

      rows.forEach((item, idx) => {
        if (!item.$modified && idx !== cIndex) {
          return;
        }

        let flag = true;

        // 向下检测
        let index = idx + 1;
        while (index < length) {
          if (item.$index >= rows[index].$index) {
            flag = false;
            break;
          }
          index++;
        }

        index = idx - 1;
        while (flag && index >= 0) {
          if (item.$index <= rows[index].$index) {
            flag = false;
            break;
          }
          index--;
        }

        if (flag) {
          toUpdate.push([idx, 1, assign({}, item, {
            $modified: false
          })]);
        } else if (idx === cIndex && idx !== item.$index) {
          toUpdate.push([idx, 1, assign({}, item, {
            $modified: true
          })]);
        }
      });

      this.setState(update(this.state, {
        rows: {
          $splice: toUpdate
        }
      }));
    }

    reset() {
      this.setState({
        rows: this.state.pristineRows,
        dragging: false,
        triggerBuild: !this.state.triggerBuild
      });
    }

    bulkGo() {
      const onBulkAction = this.props.onBulkAction;

      if (onBulkAction) {
        const rows = this.state.rows.filter(item => item.$checked);
        const uncheckedRows = this.state.rows.filter(item => !item.$checked);
        const action = this.state.bulkAction;
        onBulkAction(action.actionType, rows, action, uncheckedRows);
      }
    }

    changeRow(item, newValue, fn) {
      const idx = item.hasOwnProperty('$index') ? item.$index : this.state.rows.indexOf(item);
      const pristine = item.$pristine;
      const diffed = diff(assign({}, newValue, pristine), newValue);

      this.setState(update(this.state, {
        rows: {
          $splice: [
            [idx, 1, assign({}, item, newValue, {$modified: !isEmpty(diffed)})]
          ]
        }
      }), fn)
    }

    saveOrder() {
      const onSaveOrder = this.props.onSaveOrder;
      if (!onSaveOrder)return;

      onSaveOrder(this.state.rows);
    }

    quickSave() {
      const onQuickSave = this.props.onQuickSave;
      if (onQuickSave) {
        const rows = this.state.rows.filter(item => item.$modified);
        onQuickSave(rows);
      }
    }

    handleFieldValueChange(name, value, item) {
      if (arguments.length === 2 && name && typeof name === 'object') {
        this.changeRow(value, name);
      } else {
        this.changeRow(item, {[name]: value});
      }
    }

    handleFieldValueSave(name, value, item) {
      if (arguments.length === 2 && name && typeof name === 'object') {
        this.changeRow(value, assign({$single: true}, name), this.quickSave);
      } else {
        this.changeRow(item, {[name]: value, $single: true}, this.quickSave);
      }

    }

    refCallback(ins) {
      this.ins = ins;
    }

    handleAction(action, data, ...args) {
      const {
        onAction
      } = this.props;

      onAction && onAction(action, data, ...args);
      this.handleHighlight(data);
    }

    handleHighlight(data) {
      const {
        highlightLatestAction,
        primaryField
      } = this.props;

      if (highlightLatestAction && data && data[primaryField]) {
        this.setState({
          highlightId: data[primaryField],
          rows: this.buildRows(this.props, data[primaryField])
        });
      }
    }

    handlePageNumChange(e) {
      this.setState({
        pageNum: e.currentTarget.value
      });
    }

    renderContainer(children, defaultProps = {}) {
      const {
        $path,
        sendNotify,
        locals,
        data,
        onAction,
        onPaginationChange,
        onPerPageChange,
        currentPage,
        lastPage,
        total,
        hasMore,
        perPage,
        loading
      } = this.props;

      if (!Array.isArray(children)) {
        children = [children];
      }

      return children.map((child, key) => render(`${$path}/${child.type}`, assign({}, defaultProps, child), {
        key,
        sendNotify,
        locals,
        data,
        onRequestAction: onAction,
        onPaginationChange,
        onPerPageChange,
        currentPage,
        lastPage,
        total,
        hasMore,
        perPage,
        loading
      }));
    }

    renderToolbar(inline) {
      const {
        toolbar,
        toolbarClassName
      } = this.props;

      if (toolbar) {
        return (
          <div key="toolbar" className={toolbarClassName || (inline ? 'inline v-middle m-r-xs m-b-xs' : 'padder m-t-sm m-b-sm')}>
            <div className="table-toolbar">
              {this.renderContainer(toolbar)}
            </div>
          </div>
        );
      }
    }

    renderBulkActions(bulkActions) {
      const hasChecks = !this.state.rows.every(item => !item.$checked);
      let [btns, options] = partition(bulkActions, item => item.type === 'button');
      const {
        $path,
        loading,
        hasBulkCheckbox,
        draggable,
        data,
        headerAffix
      } = this.props;
      const {dragging} = this.state;

      const {
        rows
      } = this.state;
      const $allChecked = rows.length ? rows.every(item => item.$checked) : false;

      options = options.filter(item => item.visibleOn ? evalExpression(item.visibleOn, data) : item.hiddenOn ? !evalExpression(item.hiddenOn, data) : true);

      return (
        <div className={cx('m-b-xs')}>
          {
            (hasBulkCheckbox || headerAffix) && (btns.length || options.length) && (!draggable || (draggable && !dragging)) ?
              (
                <label className="i-checks  v-middle m-b-none m-r-sm">
                  <input type="checkbox" checked={!!$allChecked} disabled={loading} onChange={(e) => this.toggleAll(e.currentTarget.checked)} /><i />
                </label>
              ) : null
          }
          {btns.map((btn, key) => render(`${$path}/action`, btn, {
            data,
            className: cx('m-r-xs btn-sm', btn.className || 'btn-default'),
            key,
            disabled: btn.disabled || btn.disabledOn && evalExpression(btn.disabledOn, data) || !hasChecks || loading,
            onRequestAction: () => this.setState({bulkAction: btn}, this.bulkGo)
          }))}

          {options.length ? (
            <select
              className="input-sm form-control w inline v-middle"
              value={this.state.bulkAction ? options.indexOf(this.state.bulkAction) : ''}
              onChange={(e) => this.setState({bulkAction: options[e.currentTarget.value]})}
              disabled={loading}
            >
              <option value={-1}>请选择</option>
              {options.map((item, key) => (
                <option key={key} value={key} disabled={item.disabled || item.disabledOn && evalExpression(item.disabledOn, data)}>{item.label}</option>
              ))}
            </select>
          ) : null}
          {options.length ? (
            <button
              disabled={!hasChecks || !this.state.bulkAction || loading}
              onClick={this.bulkGo}
              className="btn btn-sm btn-default m-l-xs"
            >
              操作
            </button>
          ) : null}
        </div>
      );
    }

    renderLeftActions() {
      const {
        bulkActions,
        draggable,
        loading,
        hasOrder,
        hasColumTool,
        hasBulk,
        footable,
        toolbar,
        toolbarInline
      } = this.props;

      const {
        dragging,
        columnsTogglable,
        columnsTogglableCol,
        rows
      } = this.state;

      const modifiedCount = this.state.rows && this.state.rows.filter(item => item.$modified).length;
      const toggle = hasColumTool && columnsTogglable && !footable && !dragging && this.renderColumnsToggle();
      return hasOrder && draggable || toggle || hasBulk && rows.length && bulkActions &&  bulkActions.length || toolbar && toolbarInline ? (
        <div>
          {toggle}
          {hasBulk && rows.length ? (<div
            className="inline v-middle m-r-xs">{bulkActions && bulkActions.length ? this.renderBulkActions(bulkActions) : null}</div>) : null}
          {hasOrder && draggable ? (
            <div className="inline v-middle m-r-xs  m-b-xs">
              <div className="btn-group">
                <TooltipWrapper id="startDragging" tooltip="点击开始排序" placement="top">
                  <button
                    disabled={!!modifiedCount || loading}
                    onClick={this.toggleDragging}
                    className={cx('btn-sm btn btn-default', {
                      active: dragging
                    })}
                  ><i className="fa fa-bars"/></button>
                </TooltipWrapper>
              </div>
            </div>
          ) : null}
          {toolbar && toolbarInline ? this.renderToolbar(true) : null}
        </div>
      ) : null;
    }

    renderColumnsToggle() {
      const {$path} = this.props;
      const {columnsTogglableCol} = this.state;
      return columnsTogglableCol ? (
        <div className="inline v-middle m-r-xs m-b-xs">
          {
            render(`${$path}/tool`, {type: 'columnsToggle'}, assign({}, {
              cols: columnsTogglableCol,
              onColsChange: this.receiveCol
            }))
          }

          <span className="text-sm m-l-xs text-muted">配置展示项</span>
        </div>
      ) : null;
    }

    renderHeader() {
      const cols = [];
      const {
        currentPage,
        lastPage,
        total,
        hasMore,
        onPerPageChange,
        perPage,
        switchPerPage,
        onPaginationChange,
        showPagination,
        loading,
        noPanel,
        headerClassName,
        hasBulkCheckbox,
        showPageInfoOnHeader
      } = this.props;

      // 只有 table 才会上下都加
      if (!hasBulkCheckbox && loading) {
        cols.push(
          <div className="v-middle m-b-xs">
            <div className="table-info">
              <i className="fa fa-spinner fa-spin fa-2x fa-fw"/>
            </div>
          </div>
        );
      }

      const leftElement = this.renderLeftActions();
      if (leftElement) {
        cols.push(
          leftElement
        );
      }

      if (showPageInfoOnHeader) {
        loading ? cols.push(
          <div className="v-middle m-b-xs">
            <div className="table-info">
              <i className="fa fa-spinner fa-spin fa-2x fa-fw"/>
            </div>
          </div>
        ) : cols.push(
          <div className="m-b-xs m-l-xs" key="pager-info">
            <div className="table-info">{`${currentPage + '/' + lastPage}总共${total}项.`}</div>
          </div>
        );
      }

      if (switchPerPage) {
        const perPageSet = Array.isArray(switchPerPage) ? switchPerPage : [
          10, 25, 50, 100
        ];
        cols.push(
          <div className="padder-xs">
            <div className="form-inline  w-md">
            <label>每页显示
              <select className="form-control input-sm m-l-xs" value={perPage} disabled={loading}
                      onChange={ e => onPerPageChange && onPerPageChange(e.currentTarget.value)}>
                {perPageSet.map((value, key) => (
                  <option key={key} value={value}>{value}</option>
                ))}
              </select>
            </label>
          </div>
          </div>
        );
      }

      if (showPagination && lastPage > 1) {
        cols.push(
          <div className="text-right">
            <Pagination
              className={cx('pagination-sm m-t-none m-b-none inline', loading ? 'disabled' : '')}
              items={lastPage}
              maxButtons={5}
              activePage={currentPage}
              onSelect={onPaginationChange}
              prev
              next
              first
              last
              boundaryLinks
            />

            {lastPage > 9 ? (
              <div className="inline m-l-xs w-xs">
                <span className="input-group input-group-sm">
                  <input type="text" className="form-control form-control" onChange={this.handlePageNumChange} value={this.state.pageNum} />
                  <span className="input-group-btn"><button onClick={() => !loading && onPaginationChange(this.state.pageNum)} type="submit" className="btn btn-default">Go</button></span>
                </span>
              </div>
            ) : null}
          </div>
        )
      } else if (showPagination && total === 0 && (currentPage > 1 || hasMore)) {
        cols.push(
          <div className="text-right">
            <ul className="pagination pagination-sm m-t-none m-b-none">
              <li
                className={cx({
                  disabled: loading || currentPage < 2
                })}
                onClick={() => onPaginationChange && onPaginationChange(currentPage - 1, 'backward')}
              ><a><i className="fa fa-chevron-left"/></a></li>
              <li
                className={cx({
                  disabled: loading || !hasMore
                })}
                onClick={() => onPaginationChange && onPaginationChange(currentPage + 1, 'forward')}
              ><a><i className="fa fa-chevron-right"/></a></li>
            </ul>
          </div>
        )
      }

      if (!cols.length) {
        return null;
      }

      const right = cols.pop();

      return (
        <div
          key="header"
          className={cx('clearfix', typeof headerClassName === 'undefined' ? {
            'padder': !noPanel,
            'p-t-sm m-b-sm': true
          } : headerClassName)}
        >
          {cols.length ? (<div className="pull-left v-middle text-center-xs w-full-xs text-left">
            {cols.map((col, key) => React.cloneElement(col, {
              key: key,
              className: cx(col.props.className, 'inline')
            }))}
          </div>) : null }
          <div className={cx('v-middle text-center-xs w-full-xs', cols.length ? 'pull-right  text-right' : 'text-left')}>
            {right}
          </div>
        </div>
      );


      // return cols.length ? (
      //   <div
      //     className={cx('hbox','hbox-auto-xs','h-auto', typeof headerClassName === 'undefined' ? {
      //       padder: !noPanel,
      //       'm-t m-b': true
      //     } : headerClassName)}
      //   >
      //     {cols.map((col, key) => React.cloneElement(col, {
      //       key: key,
      //       className: cx(`col text-center-xs`, /\btext\-/.test(col.props.className) ? null : {
      //         'text-center': key > 0 && key < cols.length - 1,
      //         'text-right': key > 0 && key === cols.length - 1
      //       }, col.props.className)
      //     }))}
      //   </div>
      // ) : null;
    }

    renderFooter() {
      const cols = [];
      const {
        bulkActions,
        currentPage,
        lastPage,
        total,
        showPageInfo,
        onPaginationChange,
        hasMore,
        loading,
        noPanel,
        showPagination,
        footerClassName
      } = this.props;

      const {
        rows
      } = this.state;

      if (loading) {
        cols.push(
          <div className="v-middle m-b-xs">
            <div className="table-info">
              <i className="fa fa-spinner fa-spin fa-2x fa-fw"/>
            </div>
          </div>
        );
      }

      if (bulkActions && rows.length && bulkActions.length) {
        cols.push(
          this.renderBulkActions(bulkActions)
        );
      }

      if (!loading && showPageInfo && lastPage > 1) {
        cols.push(
          <div className="m-b-xs w m-l-xs" key="pager-info">
            <div className="table-info">{`${showPagination ? currentPage + '/' + lastPage + ' ' : ''}总共${total}项.`}</div>
          </div>
        );
      }

      if (showPagination && lastPage > 1) {
        cols.push(
          <div className="text-right">
            <Pagination
              className={cx('pagination-sm m-t-none m-b-none inline', loading ? 'disabled' : '')}
              items={lastPage}
              maxButtons={5}
              activePage={currentPage}
              onSelect={onPaginationChange}
              prev
              next
              first
              last
              boundaryLinks
            />

            {lastPage > 9 ? (
              <div className="inline m-l-xs w-xs">
                <span className="input-group input-group-sm">
                  <input type="text" className="form-control form-control" onChange={this.handlePageNumChange} value={this.state.pageNum} />
                  <span className="input-group-btn"><button onClick={() => !loading && onPaginationChange(this.state.pageNum)} type="submit" className="btn btn-default">Go</button></span>
                </span>
              </div>
            ) : null}
          </div>
        )
      } else if (showPagination && total === 0 && (currentPage > 1 || hasMore)) {
        cols.push(
          <div className="text-right">
            <ul className="pagination pagination-sm m-t-none m-b-none">
              <li
                className={cx({
                  disabled: loading || currentPage < 2
                })}
                onClick={() => onPaginationChange && onPaginationChange(currentPage - 1)}
              ><a><i className="fa fa-chevron-left"/></a></li>
              <li
                className={cx({
                  disabled: loading || !hasMore
                })}
                onClick={() => onPaginationChange && onPaginationChange(currentPage + 1)}
              ><a><i className="fa fa-chevron-right"/></a></li>
            </ul>
          </div>
        )
      }

      if (!cols.length) {
        return null;
      }


      const right = cols.pop();

      return (
        <footer className={cx(footerClassName, {'panel-footer': !noPanel})}>
          <div className="clearfix">
            {cols.length ? (<div className="pull-left v-middle text-center-xs w-full-xs text-left">
              {cols.map((col, key) => React.cloneElement(col, {
                key: key,
                className: cx(col.props.className, 'inline')
              }))}
            </div>) : null }
            <div className={cx('v-middle text-center-xs w-full-xs', cols.length ? 'pull-right  text-right' : 'text-left')}>
              {right}
            </div>
          </div>
        </footer>
      );

      // return cols.length ? (
      //   <footer className={cx(footerClassName, {'panel-footer': !noPanel})}>
      //     <div className="hbox hbox-auto-xs h-auto">
      //       {cols.map((col, key) => React.cloneElement(col, {
      //         key: key,
      //         className: cx(`col v-middle text-center-xs`, /\btext\-/.test(col.props.className) ? null : {
      //           'text-center': key > 0 && key < cols.length - 1,
      //           'text-right': key > 0 && key === cols.length - 1
      //         }, col.props.className)
      //       }))}
      //     </div>
      //   </footer>
      // ) : null;
    }

    render() {
      const {
        panelClassName,
        title,
        loading,
        connectDropTarget,
        data,
        hasToolBar,
        hasTool,
        hasFooter,
        noPanel,
        mode,
        toolbarInline,
        showHeader,
        showFooter,
        hideQuickSaveBtn,
        headerAffix
      } = this.props;

      const dragging = this.state.dragging;
      const state = this.state;
      const modifiedCount = state.rows && state.rows.filter(item => item.$modified).length;

      const props = pick(this, ['toggleAll', 'toggle', 'toggleDragging', 'findRow', 'moveRow', 'moveRowConfirm', 'reset', 'changeRow', 'quickSave', 'saveOrder', 'bulkGo', 'handleFieldValueChange', 'handleFieldValueSave', 'receiveCol', 'setColumnsTogglableCol', 'localSortByName']);

      const stateProps = {
        columnsTogglable: state.columnsTogglable,
        stateRows: state.rows,
        statePristineRows: state.pristineRows,
        stateBulkAction: state.bulkAction,
        stateDragging: state.dragging,
        stateTriggerBuild: state.triggerBuild,
        stateColumns: state.columns,
        stateLocalOrderBy: state.localOrderBy,
        stateLocalOrderDir: state.localOrderDir
      };

      let header = hasTool && showHeader && this.renderHeader();
      let toolbar = hasToolBar && !toolbarInline ? this.renderToolbar() : null;
      let heading = (modifiedCount && (dragging || !hideQuickSaveBtn) || title) ? (
          <div key="heading" className="panel-heading hbox h-auto">
            {modifiedCount && (dragging || !hideQuickSaveBtn) ? (
                <div className="col">
                  {dragging ? `当前有 ${modifiedCount} 条记录修改了顺序, 但并没有提交。请选择:` : `当前有 ${modifiedCount} 条记录修改了内容, 但并没有提交。请选择:`}
                  <button
                    className="btn-xs btn btn-success m-l-sm"
                    disabled={loading}
                    onClick={dragging ? this.saveOrder : this.quickSave}
                  ><i className="fa fa-check m-r-xs"/>提交</button>
                  <button
                    className="btn-xs btn btn-danger m-l-sm"
                    disabled={loading}
                    onClick={this.reset}
                  ><i className="fa fa-times m-r-xs"/>放弃</button>
                </div>
              ) : (<div className="col">{filter(title, data)}</div>)}
          </div>
        ) : null;

      if (header || toolbar || heading) {
        header = headerAffix ? (
          <AutoAffix affixClassName="crud-head-fixed" viewportOffsetTop={50}>
            <div>
              {heading}
              {toolbar}
              {header}
            </div>
          </AutoAffix>
        ) : (
            <div>
              {heading}
              {toolbar}
              {header}
            </div>
          );
      }


      return connectDropTarget(
        <div
          className={cx(noPanel ? "" : `panel panel-default panel-${mode}`, panelClassName, {
            'panel-unsaved': modifiedCount
          })}
        >

          {header}
          <ComposedComponent ref={ins=>this.ins = ins} {...this.props} {...props} {...stateProps} onAction={this.handleAction} onHighlight={this.handleHighlight} />
          {hasFooter && showFooter && this.renderFooter()}
        </div>
      );
    }
  }

  return HocCrud;
};
export default Enhance;
